/*Author:S.Genikhov
Creatin Date:
Last modified:11/Sept/2010
Reviewed by :

Version 3 with possiblitiest to : Login,get,Bye and simple Security check.
Support only TCP connection.

Short project description:
Bases reallisation of FTP server command like : cd ,send recieve file and commands,
by using of state machine*/

#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>


#include "internalftpserver.h"

#define         DEADBEAF            ((void*)0xdeadbeaf)





#ifdef _unitest_ftp_server_
static char      clientstates [][COMMANDLENGTH]={"ERR_S","USER_S","PASS_S","WAIT_S","NUMSTATE_S"};
#endif /*_unitest_ftp_server*/

int FTPClientComp(void* _oldClient,void* _newClient)
{
    return  (((FTPcln*)_oldClient)->m_key < ((FTPcln*)_newClient)->m_key);
}

int FTPLoginComp(void* _oldlog,void* _newlog)
{
    return  strcmp( (((struct userlogin*)_oldlog)->m_username),(((struct userlogin*)_newlog)->m_username) ) == -1;
}


/****************************************************************************************/

FTPServ* FTPServerNew(char* _filelogin, int _port)
{

    FTPcell         transTable[FTP_NUMEVENT_E][NUMSTATE_S]=
                {/*          ERR_S                             USER_S                       PASS_S                      WAIT_S*/
/*ERR*/          {{FTPErr       ,USER_S,USER_S},{FTPErr     ,ERR_S ,ERR_S },{FTPErr     ,ERR_S ,ERR_S },{FTPErr     ,ERR_S,ERR_S  }},
/*FTP_User_E*/   {{FTPErr       ,USER_S,USER_S},{FTPUser    ,PASS_S,USER_S},{FTPPassErr ,ERR_S ,PASS_S},{FTPCommErr ,ERR_S,WAIT_S }},
/*FTP_PASS_E*/   {{FTPErr       ,USER_S,USER_S},{FTPUserErr ,ERR_S ,USER_S},{FTPPass    ,WAIT_S,USER_S},{FTPCommErr ,ERR_S,WAIT_S }},
/*Bye      */    {{FTPUserDisc  ,ERR_S ,ERR_S },{FTPUserDisc,ERR_S ,ERR_S },{FTPUserDisc,ERR_S ,ERR_S },{FTPUserDisc,ERR_S,ERR_S  }},
/*get*/          {{FTPErr       ,USER_S,USER_S},{FTPCommErr ,ERR_S ,USER_S},{FTPPassErr ,ERR_S ,PASS_S},{FTPUserGet ,WAIT_S,WAIT_S}},
/*cd*/           {{FTPErr       ,USER_S,USER_S},{FTPCommErr ,ERR_S ,USER_S},{FTPPassErr ,ERR_S ,PASS_S},{FTPUserCd  ,WAIT_S,WAIT_S}},
/*ls*/           {{FTPErr       ,USER_S,USER_S},{FTPCommErr ,ERR_S ,USER_S},{FTPPassErr ,ERR_S ,PASS_S},{FTPls      ,WAIT_S,WAIT_S}}
                };

    FTPServ*     ft =  (FTPServ*) malloc(sizeof(FTPServ));
    if (ft == 0 )
    {
        perror("malloc :");
        fprintf(stderr,"Problems with server allocation , line: %d ",__LINE__);
        return 0;
    }

    /*Create working directory*/
    system("mkdir UsersFiles");
    if (!  getcwd(ft->m_rootdirectory,MAXIMALPATH))
    {
        free(ft);
        fprintf(stderr,"Problems with Root folder creation , line: %d , file %s ",__LINE__, __FILE__);
        return 0;
    }
    strcat(ft->m_rootdirectory,"/UsersFiles");


    ft->m_gs = FTPInitOfGenserv(ft,_port);
    if (ft->m_gs == 0 )
    {
        free(ft);
        perror("malloc :");
        fprintf(stderr,"Problems with server allocation , line: %d ",__LINE__);
        return 0;
    }

    ft->m_Clients = BinTreeNew(FTPClientComp);
    if( ft->m_Clients == 0)
    {
        GsvServerDelete(ft->m_gs);
        free(ft);
        perror("BinTreeNew :");
        fprintf(stderr,"Problems with TreeClient allocation , line: %d ",__LINE__);
        return 0;
    }

    ft->m_userlogin = BinTreeNew(FTPLoginComp);

    if(ft->m_userlogin == 0)
    {
        BinTreeDel(ft->m_Clients);
        GsvServerDelete(ft->m_gs);
        free(ft);
        perror("BinTreeNew :");
        fprintf(stderr,"Problems with Tree m_userlogin allocation , line: %d ",__LINE__);
        return 0;
    }

    if ( FTPLoadUsersFromFile(ft->m_userlogin,_filelogin) )
    {
        BinTreeDel(ft->m_userlogin);
        BinTreeDel(ft->m_Clients);
        GsvServerDelete(ft->m_gs);
        free(ft);
        fprintf(stderr,"Problems with Tree m_userlogin fill , line: %d ",__LINE__);
        return 0;
    }

/*List of events*/
    memcpy(ft->m_events,(char*)FTPevents,sizeof(ft->m_events));/*events declared in "ftpprotocol.h"*/

/*creates the transaction table*/
    memcpy(ft->m_transTable,transTable,sizeof(transTable));

    ft->m_ModeFunc[COMND_M] = FTPComMode;
    ft->m_ModeFunc[FILE_M]  = FTPFileMode;

    return ft;
}

int    FTPServerRun(FTPServ* _this)
{
    assert(_this);
   return GsvServerRun(_this->m_gs );
}
/***************************implementation of InternalFuncions************************/
GenSv* FTPInitOfGenserv(FTPServ* _ft,int _port)
{
    FTPattr*    attr;
    GenSv*      sv;
    assert(_ft);

    attr = (FTPattr*)malloc(sizeof(FTPattr));
    if (attr == 0)
    {
        perror("malloc :");
        fprintf(stderr,"Probmlems with FTPattr allocation, line : %d", __LINE__);
        return 0;
    }

    sv = GsvServerNew(_port,UDP_PORT,attr,sizeof(FTPHead),
                Headrfunc,NewClient,NewMessage,ClientDiscn,
                EXPTMESSIZE,NewExeption);

    if (sv == 0)
    {
        free(attr);
        perror("malloc :");
        fprintf(stderr,"Probmlems with param allocation of Generic server, line : %d", __LINE__);
        return 0;
    }

    attr->m_sv =  sv;
    attr->m_ft = _ft;
    return sv;
}


int FTPsecuritycheck(char* _buffer)
{
    if( strlen(_buffer) < MAXPROMTLENGH )
    {
        return 0;
    }
    return 1;
}

int FTPLoadUsersFromFile(BinTree* _userlogin,char* _filename)
{
    struct userlogin*    login;
    FILE*                fp;
    char                 line[MAXPROMTLENGH];
    char                 user[MAXPROMTLENGH];
    char                 password[MAXPROMTLENGH];
    assert(_userlogin);
    assert(_filename);

    fp = fopen(_filename,"r");
    if (fp == 0 )
    {
        fprintf(stderr,"\nWrong file name\n");
        return 1;
    }

    while(fgets(line,MAXPROMTLENGH,fp))
    {
        FTPLogFileParsing(line,user,password);
        if (strlen(user)>USERNAMESIZE  || strlen(password)>USERNAMESIZE)
        {
             fprintf(stderr,"Too long name or password line: %d, file :%s", __LINE__,__FILE__);
             continue;
        }


        login = (struct userlogin*) malloc(sizeof(struct userlogin));

        if (login == 0)
        {
            perror("malloc :");
            fprintf(stderr,"Struct login Allocation problems line: %d, file :%s", __LINE__,__FILE__);

            fclose(fp);
            FTPDeleteAllDataInTree(_userlogin);
            return 1;
        }

        strcpy(login->m_username,user);
        strcpy(login->m_userpass,password);
        login->m_logcount = 0;

        BinTreeInsert(_userlogin,login);

        if(feof(fp))
        {
            fclose(fp);
            break;
        }
    }
    return 0;
}

void FTPDeleteAllDataInTree(BinTree* _userlogin)
{
    BTreeIt     iter;
    void*        data;

    while(!BinTreeIsEmpty( _userlogin))
    {
        iter = BinTreeBegin(_userlogin);
        data = BinTreeGetData(iter);
        free(data);

#ifdef _unitest_ftp_server_
        data=DEADBEAF;
#endif

    BinTreeRemove(_userlogin,iter);
    }
}



int FTPFinedInListOfStr(char* _str, char* _liststr,int _sizeoflist, int _lenghtstr)
{
    int         i;
    assert(_str);
    assert(_liststr);

    for(i=0; i < _sizeoflist; ++i)
    {
        if ( ! strcmp(_str,_liststr+ i*_lenghtstr))
        {
            return i;
        }
    }
    return -1;
}

int FTPLogFileParsing(char* _line,OUT char* _user,OUT char* _password)
{
    char*       com;

    assert(_line);
    com = _line;


    *_user      =0;
    *_password  = 0;

     com=strtok(_line," ,\n,\t,\r");
     if(com == 0) /*Nothing promt*/
     {
         return 1;
     }
     strcpy(_user,com);
     com=strtok(NULL," ,\n,\t,\r");

     if(com!=0)
     {
         strcpy(_password,com);
     }

     else
     {
          return 1;
     }
     return 0;
}

int FTPparser(void* _buffer,OUT char* _command,OUT char* _param)
{
    char*       com;

    assert(_buffer);
    com = _buffer;
    if (FTPsecuritycheck((char*)_buffer))
    {
        fprintf(stderr,"\nTOO LONG COMMAND\n");
        return 1;
    }

    *_command=0;
    *_param  = 0;

     com=strtok(_buffer," ");
     if(com == 0) /*Nothing promt*/
     {
         return 1;
     }
     strcpy(_command,com);
     com=strtok(NULL," ");

     if(com!=0)
     {
        while(com)/*This part will be used later to devide promt in several part*/
        {
            strcat(_param,com);
            com=strtok(NULL," ");
            if(com!=0)
            {
                strcat(_param," ");
            }
        }
     }
     else
     {
         *_param=0;
     }
     return 0;
}


size_t FTPFillHeadr(INOUT void* _headbufWithData,
                        uint _positon, uint _islast, uint _error,
                        uint _datasize,uint _iscommand)

{
    FTPHead*    hd = (FTPHead*)_headbufWithData;
    size_t      headersize;
    assert(_headbufWithData);

    headersize      = sizeof(FTPHead);
    hd->m_position  = /* htonl*/(_positon);/*start position of package body*/

    hd->u_FTPbitfild.FTPUnionHeader.m_islast    =  _islast;/*is last*/
    hd->u_FTPbitfild.FTPUnionHeader.m_errnum    =  _error;/*error log*/
    hd->u_FTPbitfild.FTPUnionHeader.m_datasize  = _datasize;/*byte lenght of package body*/
    hd->u_FTPbitfild.FTPUnionHeader.m_iscommand = _iscommand;
    hd->u_FTPbitfild.FTPUnionHeader.m_reserved  = 0;

    hd->u_FTPbitfild.m_headerAsUnit = /*htonl*/(hd->u_FTPbitfild.m_headerAsUnit);


    return headersize  + _datasize;
}


void FTPReadHeadr(void* _buff,OUT FTPHead* _header)
{
     ((FTPHead*)_buff)->u_FTPbitfild.m_headerAsUnit =\
    /* ntohl*/(((FTPHead*)_buff)->u_FTPbitfild.m_headerAsUnit);

    _header->u_FTPbitfild.FTPUnionHeader.m_iscommand = ((FTPHead*)_buff)->u_FTPbitfild.FTPUnionHeader.m_iscommand;
    _header->u_FTPbitfild.FTPUnionHeader.m_datasize  = ((FTPHead*)_buff)->u_FTPbitfild.FTPUnionHeader.m_datasize;
    _header->u_FTPbitfild.FTPUnionHeader.m_errnum    = ((FTPHead*)_buff)->u_FTPbitfild.FTPUnionHeader.m_errnum;
    _header->u_FTPbitfild.FTPUnionHeader.m_islast    = ((FTPHead*)_buff)->u_FTPbitfild.FTPUnionHeader.m_islast;
    _header->u_FTPbitfild.FTPUnionHeader.m_reserved  = 0;

    _header->m_position  = /*ntohl*/(((FTPHead*)_buff)->m_position);
    return;
}

/*Get client struct*/
FTPcln* FTPGetClientStruct(int  _idclient,FTPattr* _attr)
{
    FTPcln              cl;
    FTPcln*             clptr;
    BTreeIt            clientItr;
    assert(_idclient);
    assert(_attr);

    cl.m_key = _idclient;
    clientItr = BinTreeFind(_attr->m_ft->m_Clients,&_idclient);
    if (clientItr == BinTreeEnd(_attr->m_ft->m_Clients) )
    {
        fprintf(stderr,"Illigal situation , Client not found line :%d , file :%s",__LINE__,__FILE__);
        return 0;
    }
    clptr     = (FTPcln*) BinTreeGetData(clientItr);
    return clptr ;
}

void FTPComMode(FTPattr* _attr,void* _buf,size_t _bufsize)
{
    char       command[COMMANDLENGTH]={0};
    char       param[MAXPROMTLENGH]={0};
    char       localbuf[MAXPROMTLENGH]={0};
    int        eventindex;
    int        result;


    assert(_attr);
    assert(_buf);

    memcpy(localbuf,_buf,_bufsize);

#ifdef _unitest_ftp_server_

    if ( _attr->m_cl->m_modes == COMMAND_C)
    {
        fprintf(stdout,"\nCommand arrived:  %s . Clinet initial status: %s \n",\
        localbuf,clientstates[ _attr->m_cl->m_state ] );/*clientstates - global variable*/
    }
#endif /*_unitest_ftp_server_*/


    if (FTPparser(localbuf,OUT command,OUT param))
    {

#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond : %s",FTPresponds[FTP_ILIGAL_COMND]);
fprintf(stdout,"\nERROR, next stat %s .\n",clientstates[ _attr->m_cl->m_state ]); /*clientstates - global variable*/
#endif /*_unitest_ftp_server_*/

        FTPServerRespond(_attr,FTP_ILIGAL_COMND,0);
        return;
    }

    _attr->m_param = param;


    /*need to find the appropriat event*/
    eventindex = FTPFinedInListOfStr(command,(char*)_attr->m_ft-> m_events,FTP_NUMEVENT_E,COMMANDLENGTH);
    if (eventindex == -1)
    {
        FTPServerRespond(_attr,FTP_ILIGAL_COMND,0);
#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond : %s",FTPresponds[FTP_ILIGAL_COMND]);
fprintf(stdout,"\nERROR, next stat %s .\n",clientstates[ _attr->m_cl->m_state ]); /*clientstates - global variable*/
#endif /*_unitest_ftp_server_*/
        return;
    }
    result = ((_attr->m_ft-> m_transTable[eventindex][_attr->m_cl->m_state]).m_func)(_attr);

    if (result == -1)
    {
        _attr->m_cl->m_state = (_attr->m_ft-> m_transTable[eventindex][_attr->m_cl->m_state]).m_nextfailstate;

#ifdef _unitest_ftp_server_
fprintf(stdout,"\nERROR, next stat %s .\n",clientstates[ _attr->m_cl->m_state ]); /*clientstates - global variable*/
#endif /*_unitest_ftp_server_*/

    }
    else
    {
        _attr->m_cl->m_state = (_attr->m_ft-> m_transTable[eventindex][_attr->m_cl->m_state]).m_nextstate;

#ifdef _unitest_ftp_server_
fprintf(stdout,"\nSUCCESS, next stat %s .\n",clientstates[ _attr->m_cl->m_state ]); /*clientstates - global variable*/
#endif /*_unitest_ftp_server_*/

    }
    return;
}


/****************************Transaction table function implementation********************************/
/****************************************************************************************************/
int FTPErr(FTPattr* _atr)
{
#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[FTP_WR_COM_USR]);
#endif /*_unitest_ftp_server_*/

    fprintf(stderr,"\nClient Error Status line : %d ",__LINE__);
    FTPServerRespond(_atr,FTP_WR_COM_USR,0);
    return 0;
}

int FTPUserErr(FTPattr* _atr)
{
#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[FTP_FAIL_INS_USR ]);
#endif /*_unitest_ftp_server_*/

    FTPServerRespond(_atr,FTP_FAIL_INS_USR,0);
    return -1;
}

int FTPPassErr(FTPattr* _atr)
{
#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[FTP_WR_COM_USR]);
#endif /*_unitest_ftp_server_*/

    FTPServerRespond(_atr,FTP_WR_COM_USR,0);
    return -1;
}

int FTPCommErr(FTPattr* _atr)
{

#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[FTP_ILIGAL_COMND]);
#endif /*_unitest_ftp_server_*/

     FTPServerRespond(_atr,FTP_ILIGAL_COMND,0);
    return -1;
}

void FTPServerRespond(FTPattr* _atr,FTPresp_E respIndex, char* _string)
{
    int       result =0;
    char      localbuf[MAXPROMTLENGH]={0};
    size_t    leng;

    bzero(localbuf,MAXPROMTLENGH);

    assert(_atr);

    if ( _string == 0)
    {
        leng = strlen(FTPresponds[respIndex])+1;
        memcpy(localbuf + sizeof(FTPHead),FTPresponds[respIndex],leng);
    }
    else
    {
        leng = strlen(_string)+1;
        memcpy(localbuf + sizeof(FTPHead),_string,leng);
        respIndex =  FTP_STRING;
    }

    result = FTPFillHeadr(localbuf,0,LAST_P,respIndex,leng, COMND_M);
    GsvServerWrite(_atr-> m_sv,_atr->m_cl->m_key,localbuf,result);
    return;
}



int FTPUser(FTPattr* _atr)
{
    BTreeIt            iterlogin;
    struct userlogin    user;
    struct userlogin*       testuser;

    assert(_atr);

    strcpy(user.m_username,_atr -> m_param);
    iterlogin = BinTreeFind(_atr->m_ft->m_userlogin,&user);
    if (iterlogin == BinTreeEnd (_atr->m_ft->m_userlogin) )
    {
#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[ FTP_INS_PASS]);
#endif /*_unitest_ftp_server_*/
        FTPServerRespond(_atr, FTP_INS_PASS,0);
        return -1;
    }
    else
    {
#ifdef _unitest_ftp_server_
fprintf(stdout," Server respond: %s",FTPresponds[ FTP_INS_PASS]);
#endif /*_unitest_ftp_server_*/

        testuser = BinTreeGetData(iterlogin);
        if(testuser->m_logcount == FTP_NUM_OF_WRONG_PASSW)
        {
            _atr->m_cl->m_login->m_logcount = 0;
            FTPServerRespond(_atr,FTP_USR_BLOCK,0);
            return -1;
        }
        _atr->m_cl->m_login =testuser;
        FTPServerRespond(_atr,FTP_INS_PASS,0);
    }
    return 0;
}


int FTPPass(FTPattr* _atr)
{
    assert(_atr);
    if( strcmp( _atr->m_cl->m_login->m_userpass,_atr -> m_param))
    {
        ++_atr->m_cl->m_login->m_logcount;
        if (_atr->m_cl->m_login->m_logcount == FTP_NUM_OF_WRONG_PASSW)
        {

#ifdef _unitest_ftp_server_
fprintf(stdout," Server respond:  %s",FTPresponds[FTP_FAIL_3TIME]);
#endif /*_unitest_ftp_server_*/
            _atr->m_cl->m_login = 0;
            FTPServerRespond(_atr,FTP_FAIL_3TIME,0);
            ClientDiscn(_atr->m_cl->m_key,_atr,0);
        }
        else
        {

#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[FTP_FAIL_INS_USR]);
#endif /*_unitest_ftp_server_*/

            _atr->m_cl->m_login = 0;
            FTPServerRespond(_atr,FTP_FAIL_INS_USR,0);
        }
        return -1;
    }

    else
    {
#ifdef _unitest_ftp_server_
fprintf(stdout,"Server respond: %s",FTPresponds[FTP_SUCC_WELCOME]);
#endif /*_unitest_ftp_server_*/
         _atr->m_cl->m_login->m_logcount = 0;
         FTPServerRespond(_atr,FTP_SUCC_WELCOME,0);

    }
    return 0;
}

int  FTPUserDisc(FTPattr* _atr)
{
    assert(_atr);
    _atr->m_cl->m_state = ERR_S;
    ClientDiscn(_atr->m_cl->m_key,_atr,0);

#ifdef _unitest_ftp_server_
fprintf(stdout,"\n Client sent bye.\n");
#endif /*_unitest_ftp_server_*/

    return 0;
}

int FTPUserGet(FTPattr* _atr)
{
    char    filebuffer[MAXPACKETSIZE];
    FILE*   fp;
    char*   path;
    size_t  packetsize=0;
    size_t  readed=0;
    size_t  readonce=0;
    uint    islast = NOTLAST_P;
    uint    error =0;
    size_t  lnpath;

#ifdef _unitest_ftp_server_
    FILE*   testfp;
    error =0;
    packetsize = 0;
#endif /* _unitest_ftp_server_*/

    assert(_atr);

    lnpath =  strlen(_atr->m_ft->m_rootdirectory) +strlen(_atr->m_cl->m_pwdirect) + strlen(_atr->m_param)+1;
    path=(char*)calloc(1,lnpath);
    if(path == 0)
    {
        perror("calloc :");
        fprintf(stderr,"\nAllocation problems line :%d , file %s \n", __LINE__,__FILE__);
        FTPServerRespond(_atr, FTP_SRV_ERROR,0);
        return -1;
    }
    strcpy(path,_atr->m_ft->m_rootdirectory);
    strcat(path,_atr->m_cl->m_pwdirect);
    strcat(path,_atr->m_param);


    fp = fopen(path,"r");
    if (fp == 0)
    {

        #ifdef _unitest_ftp_server_
            fprintf(stderr,"\n File was not open line: %d, file %s: \n",__LINE__,__FILE__);
        #endif /* _unitest_ftp_server_*/

        FTPServerRespond(_atr,FTP_NO_FILE,0 );
        return -1;
    }

#ifdef _unitest_ftp_server_
    testfp = fopen("chizh.odt","w");
#endif /* _unitest_ftp_server_*/

   while(islast!= LAST_P )
    {
        readonce = fread(filebuffer + sizeof(FTPHead),1,MAXPACKETSIZE-sizeof(FTPHead),fp);

#ifdef _unitest_ftp_server_
        fwrite(filebuffer,1,readonce,testfp);
#endif /* _unitest_ftp_server_*/



        if(feof(fp)) /*testing is reached the EOF*/
        {
            islast = LAST_P;
            fclose(fp);
        }

        packetsize = FTPFillHeadr(INOUT filebuffer,readed,islast ,error,readonce,FILE_C);
        readed += readonce;

#ifdef /*_DEBUG_BIT_FIELD*/_

        if (((FTPHead*)filebuffer)->u_FTPbitfild.FTPUnionHeader.m_iscommand == COMMAND_C )
        {
            fprintf(stderr,"Wrong output file sending line:%d, file: %s", __LINE__,__FILE__);
        }
#endif /*_DEBUG_BIT_FIELD*/

#ifndef _unitest_ftp_server_
        if ( GsvServerWrite(_atr->m_sv,_atr->m_cl->m_key,filebuffer,packetsize) )
        {
            fprintf(stderr,"\n GsvServerWrite problems, line: %d, file :%s\n",__LINE__,__FILE__);
            fclose(fp);
            FTPServerRespond(_atr,FTP_FILE_TRANS_ERR,0);

            return -1;
        }
#endif /*_unitest_ftp_server_*/


    }
#ifdef _unitest_ftp_server_
    fclose(testfp);
#endif /*_unitest_ftp_server_*/

    return 0;
}

int FTPUserCd(FTPattr* _atr)
{
    char*     directory = 0;
    char*     newclintdir =0;
    DIR*      dir;
    size_t    lenpath;
    int       totallenpath;
    assert(_atr);

    newclintdir = FTPMPrepareNewClientPwd(_atr,OUT &lenpath);
    if (newclintdir == 0)
    {
        return -1;
    }

    totallenpath =lenpath+ strlen(_atr->m_ft->m_rootdirectory) +1;
    directory = (char*)calloc(1,totallenpath);
    if(directory == 0)
    {
        free(newclintdir);
        perror("calloc :");
        fprintf(stderr,"\nAllocation problems line :%d , file %s \n", __LINE__,__FILE__);
        FTPServerRespond(_atr, FTP_SRV_ERROR,0);
        return -1;
    }
    strcpy(directory,_atr->m_ft->m_rootdirectory);
    strcat(directory,newclintdir);

    if (! (dir =opendir(directory)) )
    {
        FTPServerRespond(_atr,FTP_FOLDER_NOT_EXIST,0);/*Folder not existed*/
        free(newclintdir);
        return -1;
    }

    else
    {
        free(_atr->m_cl->m_pwdirect);
        _atr->m_cl->m_pwdirect = newclintdir;
        FTPServerRespond(_atr,0,_atr->m_cl->m_pwdirect);

    }

    closedir(dir);
    return 0;
}

char* FTPMPrepareNewClientPwd(FTPattr* _atr,OUT size_t* _lengpath)
{
    char*     clientdir=0;/*New client direcory resulted from adding of existed with new pass from param*/
    char*     subdirs[MAXPROMTLENGH]={0};
    char*     start=0;
    size_t    countsubdirs=0;
    size_t    ln =0;
    size_t    pathlength =0;

    assert(_atr);
    assert(_lengpath);


    /*new directpr path preparing, it takes the 1st token "experession separated by 'space' and use it as total subdirs name*/
    start = strtok(_atr->m_param," ");

    /*Non relative pass provided*/
    if (start[0] == '/')
    {

        ln = strlen(start);
        if ( *(start+ln-1) == '/')
        {
           *(start+ln-1) = 0;
             --ln;
        }
        clientdir = (char*)malloc(ln+1);
        if (clientdir == 0)
        {
            perror("malloc :");
            fprintf(stderr,"\nAllocation problems line :%d , file %s \n", __LINE__,__FILE__);
            FTPServerRespond(_atr, FTP_SRV_ERROR,0);
            return 0;
        }
        strcpy(clientdir,start);
    }
    else
    {
        /*Relative pass provided*/

        /*producing the new pass*/
        start = strtok(start,"/");
        subdirs [countsubdirs] = start;
        for(countsubdirs = 1; start; ++countsubdirs)
        {
            ln = strlen(subdirs [countsubdirs-1]);/*Calculation of totals string lengs to write the new pass*/
            start = strtok(NULL,"/");
            subdirs[countsubdirs] = start;
        }

        /*Get client directory*/
        pathlength = strlen((_atr->m_cl->m_pwdirect)) + ln +1;
        clientdir = (char*) calloc(1,pathlength);
        if (clientdir == 0)
        {
            perror("malloc :");
            fprintf(stderr,"\nAllocation problems line :%d , file %s \n", __LINE__,__FILE__);
            FTPServerRespond(_atr, FTP_SRV_ERROR,0);
            return 0;
        }

        strcpy(clientdir,_atr->m_cl->m_pwdirect);
        if ( strcmp(clientdir,"/") )/* for the follows routines i need that clientdir
                                    will not finished with '/', only if it is a root directory */
        {
            start = strrchr(clientdir,'/');
            *start = 0;
        }

        /*New paht producing*/
        countsubdirs =0;
        while (subdirs[countsubdirs])
        {
            if( !(strcmp(subdirs[countsubdirs],".")) )
            {
                ++countsubdirs;
                continue;
            }
            if (! (strcmp(subdirs[countsubdirs],"..")) )
            {
                /*Attemp to exit from root directory*/
                if ( !strcmp(clientdir,"/"))
                {
                    free(clientdir);
                    FTPServerRespond(_atr,FTP_FOLDER_NOT_EXIST,0);
                    return 0;
                }

                start = strrchr(clientdir,'/');
                *start = 0;
            }
            else
            {
                if (strcmp(clientdir,"/")) /*For root directory done need add the '/' */
                {
                    strcat(clientdir,"/");
                }
                strcat(clientdir,subdirs[countsubdirs]);
            }
            ++countsubdirs;
        }
        ln = strlen(clientdir);
    }

    /*New current pass has to be ends with '/'*/

    if ( strcmp(clientdir,"/") )
    {
        clientdir[ln]   = '/';
        clientdir[ln+1] = 0;
        *_lengpath = ln+1;
    }

    return clientdir;
}


int FTPls(FTPattr* _atr)
{
    char            directContent[MAXPACKETSIZE]={0};
    char*           dataStart;
    DIR *           dir=0;
    struct dirent*  entry=0;
    size_t          lnPath=1; /*To compensat the last '\0'*/
    size_t          headersize = sizeof(FTPHead);
    size_t          lnPresentDir;
    char*           presentDir;

    assert(_atr);
    lnPresentDir =  strlen(_atr->m_cl->m_pwdirect)+strlen(_atr->m_ft->m_rootdirectory)+1;
    presentDir = (char*)malloc(lnPresentDir);

    if (presentDir == 0)
    {
        perror(" malloc: ");
        fprintf(stderr,"\n Problems with buffer for path allocation line :%d, file :%s\n",__LINE__,__FILE__);
        FTPServerRespond(_atr,FTP_SRV_ERROR,0);
        return -1;
    }

    strcpy(presentDir,_atr->m_ft->m_rootdirectory);
    strcat(presentDir,_atr->m_cl->m_pwdirect);
    dir = opendir(presentDir);
    free(presentDir);

    dataStart =  directContent+headersize;
    if(dir == 0)
    {
        perror(" opendir: ");
        fprintf(stderr,"\n Problems with openning directory line :%d, file :%s\n",__LINE__,__FILE__);
        FTPServerRespond(_atr,FTP_SRV_ERROR,0);
        return -1;
    }

    while ( (entry = readdir(dir)) )
    {

        strcat(dataStart,entry->d_name);
        strcat(dataStart," ");
        lnPath += strlen(entry->d_name)+1;/*1 for backspace ' " */
        if (lnPath >=  MAXPACKETSIZE - headersize -256)/*Maximal size of filename in POSIX size of */
        {

            lnPath = FTPFillHeadr(directContent,0,NOTLAST_P,FTP_STRING ,lnPath,COMMAND_C);
            GsvServerWrite(_atr-> m_sv,_atr->m_cl->m_key,directContent,lnPath);
            bzero(directContent,MAXPACKETSIZE);
            lnPath =0;
        }

    }

    lnPath = FTPFillHeadr(directContent,0,LAST_P,FTP_STRING ,lnPath,COMMAND_C);
    GsvServerWrite(_atr-> m_sv,_atr->m_cl->m_key,directContent,lnPath);
    closedir(dir);
    return 0;
}

int FTPComm(FTPattr* _param)
{
#ifdef _unitest_ftp_server_
fprintf(stdout,"\nCommand done\n");
#endif /*_unitest_ftp_server_*/
    _param = 0;
    return 0;
}

void FTPFileMode(FTPattr* _attr,void* _buf,size_t _bufsize)
{

}



#ifndef _unitest_ftp_server_
int main(int argc,char* argv[])
{

    FTPServ * ft;
    int       port;
    assert(argv);
    port = atoi(argv[2]);
    ft = FTPServerNew(argv[1],port);
    FTPServerRun(ft);
    return 0;
}
#endif /*_unitest_ftp_server_*/

